package tournoi.stateless;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.PostConstruct;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import tournoi.modele.*;

@Stateless(name = "TournoiFacade", mappedName = "TournoiFacade")
public class TournoiFacadeBean implements TournoiFacadeLocal,
		TournoiFacadeRemote {

	@PersistenceContext(name = "equipes")
	EntityManager em;

	public void addArbitre(Arbitre arbitre) {
		em.persist(arbitre);
	}

	public void addArbitres(Set<Arbitre> arbitres) {
		// em.createQuery("TRUNCATE TRUNCATE Arbitre");
		for (Arbitre arbitre : arbitres)
			addArbitre(arbitre);
	}

	public void addEquipe(String nom, Set<Joueur> joueurs) {
		Equipe equipe = new Equipe();
		equipe.setNom(nom);

		for (Joueur joueur : joueurs) {
			joueur.setEquipe(equipe);
			em.persist(joueur);
		}
		equipe.setListeJoueurs(joueurs);
		em.persist(equipe);
	}

	public void affecterArbitreMatch(int match_id, int arbitre_id) {
		Match match = em.find(Match.class, match_id);
		Arbitre arbitre = em.find(Arbitre.class, arbitre_id);

		match.setArbitre(arbitre);
		em.merge(match);
	}

	public void ajouterBut(int match_id, int minute, int type_but, int joueur_id) {
		Match match = getMatchById(match_id);
		if (match != null) {
			But but = new But();
			Joueur joueur = getJoueurById(joueur_id);
			but.setButeur(joueur);
			but.setMinuteMarque(minute);
			but.setTypeBut(type_but);
			em.persist(but);

			System.out.println("But ajouté");

			match.getButs().add(but);

			match.setMinuteJoue(minute);
			em.merge(match);
		}
	}

	public void avancerMatch(int match_id, int minute) {
		Match match = getMatchById(match_id);
		if (match != null) {
			match.setMinuteJoue(minute);
			em.merge(match);
		}
	}

	public void debuterMatch(int match_id, String dateTime) {
		Match match = getMatchById(match_id);
		if (match != null) {
			match.setEtat(Match.EN_COURS);
			match.setDateHeure(dateTime);

			em.merge(match);
		}
	}

	public void finirMatch(int match_id) {
		Match match = getMatchById(match_id);
		if (match != null) {

			match.setEtat(Match.FINIT);
			if (match.isReglementaire()) {
				match.setMinuteJoue(90);
			} else {
				match.setMinuteJoue(120);
			}
			em.merge(match);
		}
	}

	public void fixerRencontres() {

		if (getAllMatch().isEmpty()) {
			// si on n'a pas de matchs, on créé le tournoi

			// 1) attribuer un numero a chaque equipe
			List<Equipe> equipes = (List<Equipe>) getAllEquipes();
			Collections.shuffle(equipes);

			System.out.println("nombre d'équipe : " + equipes.size());
			for (int i = 1; i <= equipes.size(); ++i) {
				Equipe equipe = equipes.get(i - 1);
				equipe.setNumero(i);
				em.merge(equipe);
			}

			// 2) Creer le premier tour
			Tournoi tournoi = getTournoi();

			List<Tour> tours = new ArrayList<Tour>();

			// creation des tours
			int nb_tour = 0;
			for (int t = equipes.size(); t >= 1; t /= 2) {
				nb_tour++;
				Tour tour = new Tour();
				tour.setNumero(nb_tour);
				// em.persist(tour);
				tours.add(tour);
			}

			System.out.println("Nombre de tours : " + nb_tour);

			for (int t = 0; t < tours.size(); ++t) {
				System.out.println("Tour n° : " + t);
				Tour tour = tours.get(t);

				int nb_equipes = 0;
				if (t == 0)
					nb_equipes = equipes.size();
				else
					nb_equipes = tours.get(t - 1).getMatchDuTour().size();

				System.out.println("Nombres equipes : " + nb_equipes);
				// creation des matchs du tour
				List<Match> matchs = new ArrayList<Match>();

				for (int e = 0; e < nb_equipes; e += 2) {
					Match match = new Match();
					match.setNumero(e / 2 + 1);
					match.setEtat(Match.PREVU);

					if (t >= 1 && t != (nb_tour - 1)) {
						System.out.println("erreur");
						Tour ancienTour = tours.get(t - 1);

						Match ancienMatchDomicile = ancienTour.getMatchDuTour()
								.get(e / 2);
						match.setAncienMatchDomicile(ancienMatchDomicile);

						Match ancienMatchExterieur = ancienTour
								.getMatchDuTour().get(e / 2 + 1);
						match.setAncienMatchExterieur(ancienMatchExterieur);
					} else {

						if (t == (nb_tour - 1)) {
							System.out.println("Dernier tours");
							Tour ancienTour = tours.get(t - 1);
							System.out.println("Ancien match nombre "
									+ ancienTour.getMatchDuTour().size());
							Match ancienMatchDomicile = ancienTour
									.getMatchDuTour().get(0);
							match.setAncienMatchDomicile(ancienMatchDomicile);

						} else {
							// premier match, on place les equipes

							match.setDomicile(equipes.get(e));
							match.setExterieur(equipes.get(e + 1));

						}
					}

					em.persist(match);

					if (t == (nb_tour - 1))
						tournoi.setGagnant(match);

					matchs.add(match);
				}

				tour.setMatchDuTour(matchs);

				em.persist(tour);

			}

			tournoi.setTours(new HashSet<Tour>(tours));
			tournoi.setTourEnCours(1);

			em.merge(tournoi);

		} else {
			// si on a deja des matchs

			// 1) on recupere le tour actuel
			Tournoi tournoi = getTournoi();

			int tourActuel = tournoi.getTourEnCours();
			Tour tour = getTourByNumero(tourActuel);

			boolean tous_les_matchs_finits = true;
			for (Match match : tour.getMatchDuTour()) {
				if (!match.isFinit()) {
					tous_les_matchs_finits = false;
					break;
				}
			}

			if (!tous_les_matchs_finits) {
				System.out.println("Il reste des matchs non terminés");
				return;
			} else { // seulement si tous les matchs du tour sont finits

				int numeroProchainTour = tourActuel + 1;
				Tour prochainTour = getTourByNumero(numeroProchainTour);

				for (int m = 0; m < tour.getMatchDuTour().size(); ++m) {
					Match match = tour.getMatchDuTour().get(m);

					int scoreDomicile = match.scoreEquipe(match.getDomicile());
					int scoreExterieur = match
							.scoreEquipe(match.getExterieur());

					Equipe gagnante = null;

					if (scoreDomicile > scoreExterieur)
						gagnante = match.getDomicile();
					else
						gagnante = match.getExterieur();

					if (m % 2 == 0)
						prochainTour.getMatchDuTour().get(m / 2)
								.setDomicile(gagnante);
					else
						prochainTour.getMatchDuTour().get(m / 2)
								.setExterieur(gagnante);
				}

				em.merge(prochainTour);

				tournoi.setTourEnCours(numeroProchainTour);
				em.merge(tournoi);

			}

		}

	}

	@SuppressWarnings("unchecked")
	public List<Arbitre> getAllArbitres() {
		return em.createQuery("From Arbitre a ORDER BY a.nom").getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<Equipe> getAllEquipes() {
		List<Equipe> equipes = em.createQuery("From Equipe e ORDER BY e.nom")
				.getResultList();

		if (equipes.isEmpty()) {
			remplissage();
			equipes = em.createQuery("From Equipe e ORDER BY e.nom")
					.getResultList();
		}

		return equipes;
	}

	@SuppressWarnings("unchecked")
	public List<Match> getAllMatch() {
		return em.createQuery("FROM Match m").getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<Tour> getAllTour() {
		return em.createQuery("FROM Tour m").getResultList();
	}

	public Equipe getEquipeById(int id_equipe) {
		return em.find(Equipe.class, id_equipe);
	}

	public Joueur getJoueurById(int id_joueur) {
		return em.find(Joueur.class, id_joueur);
	}

	@SuppressWarnings("unchecked")
	public List<Match> getMatchByEtat(int etat) {
		return em.createQuery(
				"FROM Match m WHERE m.etat=" + etat
						+ " AND m.domicile != NULL AND m.exterieur != NULL")
				.getResultList();
	}

	public Match getMatchById(int id_match) {
		return em.find(Match.class, id_match);
	}

	public Tour getTourByNumero(int numero) {
		return (Tour) em.createQuery("From Tour t WHERE t.numero=" + numero)
				.getSingleResult();
	}

	@SuppressWarnings("unchecked")
	public Tournoi getTournoi() {
		Tournoi tournoi;
		List<Tournoi> tournois = em.createQuery("From Tournoi t")
				.getResultList();
		if (tournois == null || tournois.size() == 0) {
			tournoi = new Tournoi();
			em.persist(tournoi);
		} else
			tournoi = tournois.get(0);

		return tournoi;
	}

	public void matchToProlongation(int match_id) {
		Match match = getMatchById(match_id);
		if (match != null) {
			match.setProlongation(true);
			match.setMinuteJoue(90);
			em.merge(match);
		}
	}

	public void matchToTirAuBut(int match_id) {
		Match match = getMatchById(match_id);
		if (match != null) {
			match.setProlongation(false);
			match.setTirAuButs(true);
			match.setMinuteJoue(120);
			em.merge(match);
		}
	}

	@PostConstruct
	public void remplissage() {

		System.out.println("Creation des equipes");

		{
			Set<Joueur> joueurs = new HashSet<Joueur>();

			Joueur kevin = new Joueur();
			kevin.setPrenom("Kevin");
			kevin.setNom("De Jesus Ferreira");
			joueurs.add(kevin);

			Joueur florent = new Joueur();
			florent.setPrenom("Florent");
			florent.setNom("Champigny");
			joueurs.add(florent);

			Joueur alex = new Joueur();
			alex.setPrenom("Alexandre");
			alex.setNom("Masson");
			joueurs.add(alex);

			Joueur tristan = new Joueur();
			tristan.setPrenom("Tristan");
			tristan.setNom("Monediere");
			joueurs.add(tristan);

			Joueur debo = new Joueur();
			debo.setPrenom("Deborah");
			debo.setNom("Del");
			joueurs.add(debo);

			Joueur juliette = new Joueur();
			juliette.setPrenom("Juliette");
			juliette.setNom("Robinet");
			joueurs.add(juliette);

			Joueur gulli = new Joueur();
			gulli.setPrenom("Gulli");
			gulli.setNom("Chat");
			joueurs.add(gulli);

			Joueur salem = new Joueur();
			salem.setPrenom("Salem");
			salem.setNom("Malikoum");
			joueurs.add(salem);

			Joueur iron = new Joueur();
			iron.setPrenom("Iron");
			iron.setNom("Chat");
			joueurs.add(iron);

			Joueur tony = new Joueur();
			tony.setPrenom("Tony");
			tony.setNom("Shtark");
			joueurs.add(tony);

			Joueur alaise = new Joueur();
			alaise.setPrenom("Alaise");
			alaise.setNom("???");
			joueurs.add(alaise);

			addEquipe("Fifo", joueurs);
		}

		{
			for (int x = 0; x < 3; ++x) {
				String nom = "Equipe" + x;

				Set<Joueur> js = new HashSet<Joueur>();
				for (int y = 0; y < 13; ++y) {
					Joueur j = new Joueur();
					j.setPrenom("Prenom[" + x + "]" + y);
					j.setNom("Nom[" + x + "]" + y);
					js.add(j);
				}
				addEquipe(nom, js);
			}
		}

		{
			Arbitre jmc = new Arbitre();
			jmc.setNom("Couvreur");
			jmc.setPrenom("Jean-Michel");
			em.persist(jmc);

			Arbitre exb = new Arbitre();
			exb.setNom("Exbrayat");
			exb.setPrenom("Matthieu");
			em.persist(exb);

			Arbitre ali = new Arbitre();
			ali.setNom("Ed-Dbali");
			ali.setPrenom("Ali");
			em.persist(ali);

			Arbitre dabro = new Arbitre();
			dabro.setNom("Dabrowski");
			dabro.setPrenom("Frederic");
			em.persist(dabro);

			Arbitre moal = new Arbitre();
			moal.setNom("Moal");
			moal.setPrenom("Frederic");
			em.persist(moal);

			Arbitre ollinger = new Arbitre();
			ollinger.setNom("Ollinger");
			ollinger.setPrenom("Nicolas");
			em.persist(ollinger);
		}

	}

	public int scoreEquipe(int id_match, int id_equipe) {
		int score = 0;

		Match match = getMatchById(id_match);

		if (match != null) {
			for (But but : match.getButs()) {
				if (but.getButeur().getEquipe().getId() == id_equipe)
					score += 1;
			}
		}

		return score;
	}
}
